package genetischeralgorithmus;

import java.util.*;
import java.awt.*;
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Dominik
 */
public class Mutation {

    public Mutation() {
    }

    public Entity[] mutate(Entity[] offspring, int mutationTyp, int mutationDegree) {

        switch (mutationTyp) {
            case 0: //none
                 return offspring;
            case 1: //DM
                return dm(offspring, mutationTyp, mutationDegree);
            case 2: // EM
                return em(offspring, mutationTyp, mutationDegree);
            case 3: //ISM
                return ism(offspring, mutationTyp, mutationDegree);
            case 4: //SIM
                return sim(offspring, mutationTyp, mutationDegree);
            case 5: //IVM
                return ivm(offspring, mutationTyp, mutationDegree);
            case 6: //SM
                return sm(offspring, mutationTyp, mutationDegree);  
        }
        return offspring;
    }

    public Entity[] dm(Entity[] offspring, int mutationTyp, int mutationDegree) {

        double mutprob = (double) mutationDegree / 100;
        int mutationCount = (int) (offspring.length * mutprob);  //ermittelt Anzahl an zu mutierenden Individuen
        Random rand1 = new Random();
        rand1.nextInt();
        for (int i = 0; i < mutationCount; i++) {
            int mutatorIndex = rand1.nextInt(offspring.length - 1);  //ermittle zu mutierendes Individuum

            Entity mutation = offspring[mutatorIndex];  //waehlt Individuum aus
            int[] unmutated = mutation.getPath();
            int[] mutated = mutation.getPath().clone();
            int l;
            int subPathPos1 = 0;
            int subPathPos2 = 0;
            int insertPos = 0;
            subPathPos1 = rand1.nextInt(unmutated.length - 1);
            subPathPos2 = getRandomWithoutX(subPathPos1, unmutated.length - 1);
            if (subPathPos2 < subPathPos1) {
                l = subPathPos1;
                subPathPos1 = subPathPos2;
                subPathPos2 = l;            }

            int subPathLength = (subPathPos2 - subPathPos1);
            insertPos = getRandomWithoutX(subPathPos1, unmutated.length - 1 - subPathLength);
            int movingDistance = insertPos - subPathPos1; //beschreibt die Entfernung der alten zur neuen subPath position (kann negativ sein)

            for (int j = insertPos; j < insertPos + subPathLength; j++) {
                mutated[j] = unmutated[j - movingDistance];
            }
            int switchPos = 0;
            for (int j = 0; j < subPathPos1; j++) {

                if (switchPos >= insertPos && switchPos <= insertPos + subPathLength) {
                    switchPos += subPathLength;
                }
                mutated[switchPos++] = unmutated[j];
            }
            for (int j = subPathPos2; j < mutated.length; j++) {
                if (switchPos >= insertPos && switchPos <= insertPos + subPathLength) {
                    switchPos += subPathLength;
                }
                mutated[switchPos++] = unmutated[j];
            }
            mutation.setPath(mutated);
            offspring[mutatorIndex] = mutation;
        }
        return offspring;
    }

    public Entity[] em(Entity[] offspring, int mutationTyp, int mutationDegree) {

        double mutprob = (double) mutationDegree / 100;
        int mutationCount = (int) (offspring.length * mutprob);  //ermittelt Anzahl an zu mutierenden Individuen
        Random rand1 = new Random();
        rand1.nextInt();
        for (int i = 0; i < mutationCount; i++) {
            int mutatorIndex = rand1.nextInt(offspring.length);  //ermittle zu mutierendes Individuum
            int[] mutation = offspring[mutatorIndex].getPath();
            int pos1 = rand1.nextInt(mutation.length - 1);
            int pos2 = getRandomWithoutX(pos1, mutation.length);
            int temp = mutation[pos1];
            mutation[pos1] = mutation[pos2];
            mutation[pos2] = temp;
            offspring[mutatorIndex].setPath(mutation);
        }
        return offspring;
    }

    public Entity[] ism(Entity[] offspring, int mutationTyp, int mutationDegree) {

        double mutprob = (double) mutationDegree / 100;
        int mutationCount = (int) (offspring.length * mutprob);  //ermittelt Anzahl an zu mutierenden Individuen

        Random rand1 = new Random();
        rand1.nextInt();

        for (int i = 0; i < mutationCount; i++) {
            int mutatorIndex = rand1.nextInt(offspring.length - 1);  //ermittle zu mutierendes Individuum

            int[] mutation = offspring[mutatorIndex].getPath();

            int pos1 = rand1.nextInt(mutation.length - 1);
            int pos2 = getRandomWithoutX(pos1, mutation.length - 1);
            int l;
            if (pos2 < pos1) {
                l = pos1;
                pos1 = pos2;
                pos2 = l;
            }

            int temp = mutation[pos1];

            for (int j = pos1; j < pos2; j++) {
                mutation[j] = mutation[j + 1];
            }

            mutation[pos2] = temp;

            offspring[mutatorIndex].setPath(mutation);

        }
        return offspring;


    }

    public Entity[] sim(Entity[] offspring, int mutationTyp, int mutationDegree) {

        double mutprob = (double) mutationDegree / 100;
        int mutationCount = (int) (offspring.length * mutprob);  //ermittelt Anzahl an zu mutierenden Individuen

        Random rand1 = new Random();
        rand1.nextInt();

        for (int i = 0; i < mutationCount; i++) {
            int mutatorIndex = rand1.nextInt(offspring.length - 1);  //ermittle zu mutierendes Individuum

            int[] mutation = offspring[mutatorIndex].getPath();

            int pos1 = rand1.nextInt(mutation.length - 1);
            int pos2 = getRandomWithoutX(pos1, mutation.length - 1);
            int l;
            if (pos2 < pos1) {
                l = pos1;
                pos1 = pos2;
                pos2 = l;
            }

            
            System.out.println("unmutated: "+Arrays.toString(mutation));


            int k= pos2;
            for (int j = pos1; j <= ((pos1+(pos2-pos1))/2); j++) {
                int temp = mutation[j];
                mutation[j] = mutation[k];
                mutation[k--]=temp;
            }

            System.out.println("mutated  : "+Arrays.toString(mutation));

            offspring[mutatorIndex].setPath(mutation);

        }
        return offspring;

    }

    public Entity[] ivm(Entity[] offspring, int mutationTyp, int mutationDegree) {

        return offspring;

    }

    public Entity[] sm(Entity[] offspring, int mutationTyp, int mutationDegree) {

        return offspring;

    }

    public int getRandomWithoutX(int x, int max) {
        boolean found = false;
        int random = 0;
        while (!found) {
            random = new Random().nextInt(max);
            if (random != x) {
                found = true;
            }
        }
        return random;
    }
}


